//
// Created by 崔世强 on 2018/3/27.
// Copyright (c) 2018 Facebook. All rights reserved.
//

import Foundation
import WCDBSwift
import SwiftyJSON

class GroupService {
    
    var db: Database
    
    init() {
        db = SQLiteHelper.getDb()
    }
    
    private let contactService = ContactService()
    
    func getGroupInfoFromRemote(_ groupId:Int,queue:DispatchQueue) throws {
        IM.request(.getGroupInfo(groupId: groupId),success: { (json) in
            if reqSuccess(json["code"].stringValue) {
                do {
                    let groupName = json["res","groupName"].string
                    let announcement = json["res","announcement"].string
                    let type = json["res","type"].intValue
                    let mute = json["res","mute"].boolValue
                    let avatar = json["res","avatar"].string
                    let ownerId = json["res","ownerId"].intValue
                    try self.db.run(transaction: { [unowned self] _ in
                        if let groupInDb:Group = try GroupDao.getGroup(groupId) {
                            groupInDb.name = groupName
                            groupInDb.avatar = avatar
                            groupInDb.announcement = announcement
                            groupInDb.mute = mute
                            groupInDb.owner = ownerId
                            groupInDb.deleted = false
                            groupInDb.kickout = false
                            try self.db.update(table: Group.table,on: [Group.CodingKeys.name,Group.CodingKeys.deleted],with: groupInDb,where:Group.CodingKeys.groupId == groupId)
                        } else {
                            let groupToSave = Group()
                            groupToSave.groupId = groupId
                            groupToSave.name = groupName
                            groupToSave.avatar = avatar
                            groupToSave.announcement = announcement
                            groupToSave.mute = mute
                            groupToSave.owner = ownerId
                            groupToSave.groupType = GroupType(rawValue: type) ?? GroupType.normal
                            groupToSave.deleted = false
                            try self.db.insert(groupToSave, intoTable: Group.table)
                        }
                    })
                    
                    for memberJson in json["res","groupUsers"].arrayValue {
                        let userId = memberJson["userId"].intValue
                        let me = (userId == AppStatusManager.instance.userLoginStatus.1 ?? 0)
                        let nickName = memberJson["nickName"].string
                        let mute = memberJson["mute"].boolValue
                        let memberType = memberJson["memberType"].intValue
                        let member = GroupMember()
                        member.groupId = groupId
                        member.userId = userId
                        member.nickName = nickName
                        member.mute = mute
                        member.memberType = GroupMemberType(rawValue: memberType) ?? GroupMemberType.normal
                        member.me = me
                        
                        try self.db.run(transaction: { [unowned self] _ in
                            if try ContactDao.getContact(userId) == nil  {
                                self.contactService.syncUserInfo(userId,queue:queue)
                            }
                            let count = try self.db.getValue(on: GroupMember.CodingKeys.any.count(), fromTable: GroupMember.table,
                                                             where: GroupMember.CodingKeys.groupId == groupId && GroupMember.CodingKeys.userId == userId)
                            if count.int64Value == 0 {
                                try self.db.insert(member, intoTable: GroupMember.table)
                            } else {
                                try self.db.update(table: GroupMember.table,
                                                   on: [GroupMember.CodingKeys.nickName,GroupMember.CodingKeys.deleted,GroupMember.CodingKeys.mute,GroupMember.CodingKeys.memberType,GroupMember.CodingKeys.me],
                                                   with: member,
                                                   where: GroupMember.CodingKeys.groupId == groupId && GroupMember.CodingKeys.userId == userId)
                            }
                        })
                        
                    }
                    DispatchQueue.main.async {
                        let dic:[String:Any] = ["groupId":groupId,"mute":mute]
                        NotificationCenter.default.post(name: NSNotification.Name(rawValue: kNoteChatMsgGroupMute), object: dic)
                    }
                } catch {
                    print(error)
                }
            } else {
                let msg = json["msg"].stringValue
                print(msg)
            }
        }, error: { (code) in
            print("状态异常：\(code)")
        }) { (error) in
            print(error)
        }
    }
    
    func getChatGroupMembers(_ groupId: Int, limit: Int) throws -> [ChatGroupMember] {
        var chatGroupMembers = [ChatGroupMember]()
        try db.run(transaction: { _ in
            let members = try GroupDao.getMembers(groupId, limit: limit)
            for member in members {
                let contact: Contact? = try ContactDao.getContact(member.userId)
                let chatGroupMember = ChatGroupMember()
                chatGroupMember.groupId = member.groupId
                chatGroupMember.nickName = member.nickName ?? contact?.remarkName ?? contact?.name ?? "未知"
                chatGroupMember.deleted = member.deleted
                chatGroupMember.me = member.me
                chatGroupMember.mute = member.mute
                chatGroupMember.memberType = member.memberType
                chatGroupMember.contact = contact
                chatGroupMember.id = member.id
                chatGroupMember.userId = member.userId
                chatGroupMembers.append(chatGroupMember)
            }
        })
        return chatGroupMembers
    }
    
    func createNewGroup(name:String?, createUserId:Int, ids: [Int],callback:@escaping (_ success:Bool,_ msg:String,_ groupId:Int) -> Void) throws {
        IM.request(.createNewGroup(name: name, type: GroupType.normal.rawValue, createUserId: createUserId, ids: ids),success: { (json) in
            if reqSuccess(json["code"].stringValue) {
                do {
                    let groupId = json["res"].intValue
                    let db = SQLiteHelper.getDb()
                    try db.run(transaction: { _ in
                        _ = try GroupDao.createNewGroup(groupId: groupId, name: name, type: GroupType.normal, createUserId: createUserId, ids: ids)
                        let session = Session()
                        session.sessionServerId = groupId
                        session.chatType = .group
                        _ = try SessionDao.save(session)
                    })
                    callback(true,"建群成功",groupId)
                } catch {
                    print(error)
                }
            } else {
                let msg = json["msg"].stringValue
                print(msg)
                callback(false,msg,0)
            }
        }, error: { (code) in
            print("状态异常：\(code)")
            callback(false,"建群失败",0)
        }) { (error) in
            print(error)
            callback(false,"建群失败",0)
        }
        
    }
    
    func getMyInfo(_ groupId: Int) throws -> ChatGroupMember? {
        let chatGroupMember = ChatGroupMember()
        try db.run(transaction: { _ in
            if let member = try GroupDao.getMember(groupId, userId: AppStatusManager.instance.userLoginStatus.1 ?? 0) {
                let contact: Contact? = try ContactDao.getContact(member.userId)
                chatGroupMember.groupId = member.groupId
                chatGroupMember.nickName = member.nickName
                chatGroupMember.deleted = member.deleted
                chatGroupMember.me = member.me
                chatGroupMember.mute = member.mute
                chatGroupMember.memberType = member.memberType
                chatGroupMember.contact = contact
                chatGroupMember.id = member.id
                chatGroupMember.userId = member.userId
            }
        })
        return chatGroupMember
    }
    
    func getGroupMember(_ groupId:Int,memberId:Int) -> ChatGroupMember? {
        do {
            let chatGroupMember = ChatGroupMember()
            try db.run(transaction: { _ in
                if let member = try GroupDao.getMember(groupId, userId: memberId) {
                    let contact: Contact? = try ContactDao.getContact(member.userId)
                    chatGroupMember.groupId = member.groupId
                    chatGroupMember.nickName = member.nickName
                    chatGroupMember.deleted = member.deleted
                    chatGroupMember.me = member.me
                    chatGroupMember.mute = member.mute
                    chatGroupMember.memberType = member.memberType
                    chatGroupMember.contact = contact
                    chatGroupMember.id = member.id
                    chatGroupMember.userId = member.userId
                }
            })
            return chatGroupMember
        } catch {
            return nil
        }
    }
    
    func getGroupMemberIdSet(_ groupId: Int, limit: Int) throws -> Set<Int> {
        var idSet:Set<Int> = Set<Int>()
        try db.run(transaction: { _ in
            let members = try GroupDao.getMembers(groupId, limit: limit)
            for member in members {
                idSet.insert(member.userId)
            }
            
        })
        return idSet
    }
    
    func delete(_ groupId: Int, members: [Int]) throws {
        try db.run(transaction: { _ in
            try GroupDao.delete(groupId, userIds: members)
        })
    }
    
    
    func update(_ groupId: Int, withName: String) throws {
        try db.run(transaction: { _ in
            try GroupDao.updateGroupName(groupId, name: withName)
        })
    }
    
    func update(_ groupId: Int, withAnnouncement: String) throws {
        try db.run(transaction: { _ in
            try GroupDao.updateAnnouncement(groupId, announcement: withAnnouncement)
        })
    }
    
    func update(_ groupId: Int,userId:Int, withNickName: String) throws {
        try db.run(transaction: { _ in
            try GroupDao.updateMemberNickName(groupId,userId:userId, nickName: withNickName)
        })
    }
    
    func update(_ groupId: Int, withTop: Bool) throws {
        try db.run(transaction: { _ in
            try GroupDao.updateTop(groupId, top: withTop)
            try SessionDao.updateTop(groupId,top:withTop)
        })
    }
    func update(_ groupId: Int, withMuteAll: Bool) throws {
        try db.run(transaction: { _ in
            try GroupDao.updateMuteAll(groupId, muteAll: withMuteAll)
        })
    }
    
    func update(_ groupId: Int, withNoDisturb: Bool) throws {
        try db.run(transaction: { _ in
            try GroupDao.updateNoDisturb(groupId, noDisturb: withNoDisturb)
        })
    }
    
    func quit(_ groupId: Int) throws {
        try db.run(transaction: { _ in
            try GroupDao.quit(groupId)
            try SessionDao.delete(groupId)
        })
    }
    
    func add(_ id: Int!, members: [Int]) throws {
        try db.run(transaction: { _ in
            for userId in members {
                if let groupMember = try GroupDao.getMemberWithoutDeleted(id, userId: userId) {
                    groupMember.deleted = false
                    try GroupDao.updateMember(id,userId:userId,deleted:false)
                } else {
                    let groupMember = GroupMember()
                    groupMember.userId = userId
                    groupMember.groupId = id
                    _ = try GroupDao.insert(groupMember)
                }
            }
        })
    }
}
